package org.eiahe.hr.salary.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.ehe.common.core.utils.MapstructUtils;
import org.ehe.common.core.utils.StringUtils;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.ehe.system.domain.vo.SysDeptVo;
import org.ehe.system.service.ISysDeptService;
import org.eiahe.hr.salary.domain.SalaryStructure;
import org.eiahe.hr.salary.domain.bo.SalaryStructureBo;
import org.eiahe.hr.salary.domain.vo.SalaryStructureVo;
import org.eiahe.hr.salary.domain.vo.EmployeeSalaryVo;
import org.eiahe.hr.salary.mapper.SalaryStructureMapper;
import org.eiahe.hr.salary.service.ISalaryStructureService;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 薪资构成Service业务层处理
 *
 * @author zhangnn
 */
@RequiredArgsConstructor
@Service
public class SalaryStructureServiceImpl implements ISalaryStructureService {

    private final SalaryStructureMapper baseMapper;
    private final ISysDeptService deptService;

    @Override
    public SalaryStructureVo queryById(Long structureId) {
        SalaryStructureVo vo = baseMapper.selectVoById(structureId);
        String department = vo.getDepartment();
        SysDeptVo sysDeptVo = deptService.selectDeptById(Long.valueOf(department));
        if (Objects.nonNull(sysDeptVo)) {
            vo.setDepartmentName(sysDeptVo.getDeptName());
        }
        return vo;
    }

    @Override
    public List<SalaryStructureVo> queryList(SalaryStructureBo bo) {
        LambdaQueryWrapper<SalaryStructure> lqw = buildQueryWrapper(bo);
        List<SalaryStructureVo> salaryStructureVos = baseMapper.selectVoList(lqw);
        salaryStructureVos.forEach(p -> {
            String department = p.getDepartment();
            SysDeptVo sysDeptVo = deptService.selectDeptById(Long.valueOf(department));
            if (Objects.nonNull(sysDeptVo)) {
                p.setDepartmentName(sysDeptVo.getDeptName());
            }
        });
        return salaryStructureVos;
    }

    @Override
    public TableDataInfo<SalaryStructureVo> queryPageList(SalaryStructureBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SalaryStructure> lqw = buildQueryWrapper(bo);
        IPage<SalaryStructureVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        result.getRecords().forEach(p -> {
            String department = p.getDepartment();
            if(StringUtils.isNotBlank(department)){
                SysDeptVo sysDeptVo = deptService.selectDeptById(Long.valueOf(department));
                if (Objects.nonNull(sysDeptVo)) {
                    p.setDepartmentName(sysDeptVo.getDeptName());
                }
            }
        });
        return TableDataInfo.build(result);
    }

    @Override
    public Boolean insertByBo(SalaryStructureBo bo) {
        SalaryStructure add = MapstructUtils.convert(bo, SalaryStructure.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setStructureId(add.getStructureId());
        }
        return flag;
    }

    @Override
    public Boolean updateByBo(SalaryStructureBo bo) {
        SalaryStructure update = MapstructUtils.convert(bo, SalaryStructure.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids) {
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 员工查询自己的薪资列表（敏感信息已模糊处理）
     *
     * @param employeeNo 工号
     * @param yearMonth  年月(yyyyMM格式)
     * @return 员工薪资列表
     */
    @Override
    public List<EmployeeSalaryVo> queryEmployeeSalaryList(String employeeNo, String yearMonth) {
        LambdaQueryWrapper<SalaryStructure> lqw = Wrappers.lambdaQuery();
        lqw.eq(SalaryStructure::getEmployeeNo, employeeNo);
        if (StringUtils.isNotBlank(yearMonth)) {
            lqw.eq(SalaryStructure::getYearMonth, yearMonth);
        }
        lqw.eq(SalaryStructure::getStatus, "0"); // 只查询正常状态的数据
        lqw.orderByDesc(SalaryStructure::getYearMonth);

        List<SalaryStructure> salaryList = baseMapper.selectList(lqw);
        return salaryList.stream()
                .map(this::convertToEmployeeSalaryVo)
                .collect(Collectors.toList());
    }

    /**
     * 员工分页查询自己的薪资列表（敏感信息已模糊处理）
     *
     * @param employeeNo 工号
     * @param yearMonth  年月(yyyyMM格式)
     * @param pageQuery  分页参数
     * @return 员工薪资分页数据
     */
    @Override
    public TableDataInfo<EmployeeSalaryVo> queryEmployeeSalaryPageList(String employeeNo, String yearMonth,
            PageQuery pageQuery) {
        LambdaQueryWrapper<SalaryStructure> lqw = Wrappers.lambdaQuery();
        lqw.eq(SalaryStructure::getEmployeeNo, employeeNo);
        if (StringUtils.isNotBlank(yearMonth)) {
            lqw.eq(SalaryStructure::getYearMonth, yearMonth);
        }
        lqw.eq(SalaryStructure::getStatus, "0"); // 只查询正常状态的数据
        lqw.orderByDesc(SalaryStructure::getYearMonth);

        Page<SalaryStructure> page = baseMapper.selectPage(pageQuery.build(), lqw);
        List<EmployeeSalaryVo> employeeSalaryVos = page.getRecords().stream()
                .map(this::convertToEmployeeSalaryVo)
                .collect(Collectors.toList());
        employeeSalaryVos.forEach(p -> {
            String department = p.getDepartment();
            if(StringUtils.isNotBlank(department)){
                SysDeptVo sysDeptVo = deptService.selectDeptById(Long.valueOf(department));
                if (Objects.nonNull(sysDeptVo)) {
                    p.setDepartmentName(sysDeptVo.getDeptName());
                }
            }
        });

        Page<EmployeeSalaryVo> resultPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        resultPage.setRecords(employeeSalaryVos);
        return TableDataInfo.build(resultPage);
    }

    /**
     * 根据ID获取员工薪资详情（可选择是否脱敏）
     *
     * @param structureId 薪资构成ID
     * @param maskData    是否脱敏数据
     * @return 员工薪资详情
     */
    @Override
    public EmployeeSalaryVo getEmployeeSalaryDetail(Long structureId, boolean maskData) {
        SalaryStructure salaryStructure = baseMapper.selectById(structureId);
        if (salaryStructure == null) {
            return null;
        }

        if (maskData) {
            EmployeeSalaryVo vo = convertToEmployeeSalaryVo(salaryStructure);
            vo.setIsMasked(true);
            return vo;
        } else {
            EmployeeSalaryVo vo = convertToEmployeeSalaryVoWithFullData(salaryStructure);
            vo.setIsMasked(false);
            return vo;
        }
    }

    /**
     * 模糊处理薪资金额
     *
     * @param amount 金额
     * @return 模糊处理后的金额字符串（如 *****）
     */
    @Override
    public String maskSalaryAmount(BigDecimal amount) {
        // 所有金额统一脱敏为 ***** 格式
        return "*****";
    }

    /**
     * 将SalaryStructure转换为EmployeeSalaryVo（敏感信息模糊处理）
     *
     * @param salaryStructure 薪资结构实体
     * @return 员工薪资VO
     */
    private EmployeeSalaryVo convertToEmployeeSalaryVo(SalaryStructure salaryStructure) {
        EmployeeSalaryVo vo = new EmployeeSalaryVo();
        vo.setStructureId(salaryStructure.getStructureId());
        vo.setEmployeeNo(salaryStructure.getEmployeeNo());
        vo.setEmployeeName(salaryStructure.getEmployeeName());
        vo.setDepartment(salaryStructure.getDepartment());
        vo.setYearMonth(salaryStructure.getYearMonth());
        vo.setShouldAttendanceDays(salaryStructure.getShouldAttendanceDays());
        vo.setAbsenceDays(salaryStructure.getAbsenceDays());
        vo.setPaidAttendanceDays(salaryStructure.getPaidAttendanceDays());

        // 时间类型转换
        vo.setCreateTime(salaryStructure.getCreateTime());
        vo.setUpdateTime(salaryStructure.getUpdateTime());

        // 对薪资相关字段进行模糊处理
        vo.setJobLevelSalary(salaryStructure.getJobLevelSalary());
        vo.setBaseSalary(maskSalaryAmount(salaryStructure.getBaseSalary()));
        vo.setPositionSalary(maskSalaryAmount(salaryStructure.getPositionSalary()));
        vo.setPerformanceSalary(maskSalaryAmount(salaryStructure.getPerformanceSalary()));
        vo.setDutyAllowance(maskSalaryAmount(salaryStructure.getDutyAllowance()));
        vo.setAbsenceDeduction(maskSalaryAmount(salaryStructure.getAbsenceDeduction()));
        vo.setMealAllowance(maskSalaryAmount(salaryStructure.getMealAllowance()));
        vo.setOtherAdjustment(maskSalaryAmount(salaryStructure.getOtherAdjustment()));
        vo.setMealDeduction(maskSalaryAmount(salaryStructure.getMealDeduction()));
        vo.setGrossSalary(maskSalaryAmount(salaryStructure.getGrossSalary()));
        vo.setPensionDeduction(maskSalaryAmount(salaryStructure.getPensionDeduction()));
        vo.setUnemploymentDeduction(maskSalaryAmount(salaryStructure.getUnemploymentDeduction()));
        vo.setMedicalDeduction(maskSalaryAmount(salaryStructure.getMedicalDeduction()));
        vo.setMajorMedicalDeduction(maskSalaryAmount(salaryStructure.getMajorMedicalDeduction()));
        vo.setSocialInsurancePersonal(maskSalaryAmount(salaryStructure.getSocialInsurancePersonal()));
        vo.setHousingFundPersonal(maskSalaryAmount(salaryStructure.getHousingFundPersonal()));
        vo.setSocialHousingTotal(maskSalaryAmount(salaryStructure.getSocialHousingTotal()));
        vo.setTaxableSalary(maskSalaryAmount(salaryStructure.getTaxableSalary()));
        vo.setPersonalTax(maskSalaryAmount(salaryStructure.getPersonalTax()));
        vo.setNetSalary(maskSalaryAmount(salaryStructure.getNetSalary()));
        vo.setIsMasked(true); // 标记为已脱敏数据

        return vo;
    }

    /**
     * 将SalaryStructure转换为EmployeeSalaryVo（完整数据，不脱敏）
     *
     * @param salaryStructure 薪资结构实体
     * @return 员工薪资VO
     */
    private EmployeeSalaryVo convertToEmployeeSalaryVoWithFullData(SalaryStructure salaryStructure) {
        EmployeeSalaryVo vo = new EmployeeSalaryVo();
        vo.setStructureId(salaryStructure.getStructureId());
        vo.setEmployeeNo(salaryStructure.getEmployeeNo());
        vo.setEmployeeName(salaryStructure.getEmployeeName());
        vo.setDepartment(salaryStructure.getDepartment());
        vo.setYearMonth(salaryStructure.getYearMonth());
        vo.setShouldAttendanceDays(salaryStructure.getShouldAttendanceDays());
        vo.setAbsenceDays(salaryStructure.getAbsenceDays());
        vo.setPaidAttendanceDays(salaryStructure.getPaidAttendanceDays());

        // 时间类型转换
        vo.setCreateTime(salaryStructure.getCreateTime());
        vo.setUpdateTime(salaryStructure.getUpdateTime());

        // 不进行模糊处理，直接显示完整数据
        vo.setJobLevelSalary(salaryStructure.getJobLevelSalary());
        vo.setBaseSalary(formatAmount(salaryStructure.getBaseSalary()));
        vo.setPositionSalary(formatAmount(salaryStructure.getPositionSalary()));
        vo.setPerformanceSalary(formatAmount(salaryStructure.getPerformanceSalary()));
        vo.setDutyAllowance(formatAmount(salaryStructure.getDutyAllowance()));
        vo.setAbsenceDeduction(formatAmount(salaryStructure.getAbsenceDeduction()));
        vo.setMealAllowance(formatAmount(salaryStructure.getMealAllowance()));
        vo.setOtherAdjustment(formatAmount(salaryStructure.getOtherAdjustment()));
        vo.setMealDeduction(formatAmount(salaryStructure.getMealDeduction()));
        vo.setGrossSalary(formatAmount(salaryStructure.getGrossSalary()));
        vo.setPensionDeduction(formatAmount(salaryStructure.getPensionDeduction()));
        vo.setUnemploymentDeduction(formatAmount(salaryStructure.getUnemploymentDeduction()));
        vo.setMedicalDeduction(formatAmount(salaryStructure.getMedicalDeduction()));
        vo.setMajorMedicalDeduction(formatAmount(salaryStructure.getMajorMedicalDeduction()));
        vo.setSocialInsurancePersonal(formatAmount(salaryStructure.getSocialInsurancePersonal()));
        vo.setHousingFundPersonal(formatAmount(salaryStructure.getHousingFundPersonal()));
        vo.setSocialHousingTotal(formatAmount(salaryStructure.getSocialHousingTotal()));
        vo.setTaxableSalary(formatAmount(salaryStructure.getTaxableSalary()));
        vo.setPersonalTax(formatAmount(salaryStructure.getPersonalTax()));
        vo.setNetSalary(formatAmount(salaryStructure.getNetSalary()));
        vo.setIsMasked(false); // 标记为未脱敏数据

        return vo;
    }

    /**
     * 格式化金额显示
     *
     * @param amount 金额
     * @return 格式化后的金额字符串
     */
    private String formatAmount(BigDecimal amount) {
        if (amount == null) {
            return "¥0.00";
        }
        DecimalFormat df = new DecimalFormat("#,##0.00");
        return "¥" + df.format(amount);
    }

    /**
     * 构建查询条件
     *
     * @param bo 薪资构成业务对象
     * @return 查询条件
     */
    private LambdaQueryWrapper<SalaryStructure> buildQueryWrapper(SalaryStructureBo bo) {
        LambdaQueryWrapper<SalaryStructure> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getEmployeeNo()), SalaryStructure::getEmployeeNo, bo.getEmployeeNo());
        lqw.eq(StringUtils.isNotBlank(bo.getEmployeeName()), SalaryStructure::getEmployeeName, bo.getEmployeeName());
        lqw.eq(StringUtils.isNotBlank(bo.getYearMonth()), SalaryStructure::getYearMonth, bo.getYearMonth());
        lqw.eq(StringUtils.isNotBlank(bo.getDepartment()), SalaryStructure::getDepartment, bo.getDepartment());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SalaryStructure::getStatus, bo.getStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getDataSource()), SalaryStructure::getDataSource, bo.getDataSource());
        lqw.orderByDesc(SalaryStructure::getCreateTime);
        return lqw;
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(SalaryStructure entity) {
        // 校验员工工号是否存在
        if (StringUtils.isBlank(entity.getEmployeeNo())) {
            throw new RuntimeException("员工工号不能为空");
        }

        // 校验年月格式
        if (StringUtils.isBlank(entity.getYearMonth()) || entity.getYearMonth().length() != 6 ||
                !entity.getYearMonth().matches("\\d{6}")) {
            throw new RuntimeException("年月格式不正确，请使用yyyyMM格式");
        }

        // 自动计算应发工资（如果没有提供的话）
        if (entity.getGrossSalary() == null) {
            BigDecimal calculatedGross = BigDecimal.ZERO;
            if (entity.getBaseSalary() != null)
                calculatedGross = calculatedGross.add(entity.getBaseSalary());
            if (entity.getPerformanceSalary() != null)
                calculatedGross = calculatedGross.add(entity.getPerformanceSalary());
            if (entity.getDutyAllowance() != null)
                calculatedGross = calculatedGross.add(entity.getDutyAllowance());
            if (entity.getMealAllowance() != null)
                calculatedGross = calculatedGross.add(entity.getMealAllowance());
            if (entity.getOtherAdjustment() != null)
                calculatedGross = calculatedGross.add(entity.getOtherAdjustment());
            if (entity.getAbsenceDeduction() != null)
                calculatedGross = calculatedGross.subtract(entity.getAbsenceDeduction());
            if (entity.getMealDeduction() != null)
                calculatedGross = calculatedGross.subtract(entity.getMealDeduction());
            entity.setGrossSalary(calculatedGross);
        } else {
            // 校验薪资构成的数学校验（应发 = 基本工资+绩效+补贴-扣除项）
            BigDecimal calculatedGross = BigDecimal.ZERO;
            if (entity.getBaseSalary() != null)
                calculatedGross = calculatedGross.add(entity.getBaseSalary());
            if (entity.getPerformanceSalary() != null)
                calculatedGross = calculatedGross.add(entity.getPerformanceSalary());
            if (entity.getDutyAllowance() != null)
                calculatedGross = calculatedGross.add(entity.getDutyAllowance());
            if (entity.getMealAllowance() != null)
                calculatedGross = calculatedGross.add(entity.getMealAllowance());
            if (entity.getOtherAdjustment() != null)
                calculatedGross = calculatedGross.add(entity.getOtherAdjustment());
            if (entity.getAbsenceDeduction() != null)
                calculatedGross = calculatedGross.subtract(entity.getAbsenceDeduction());
            if (entity.getMealDeduction() != null)
                calculatedGross = calculatedGross.subtract(entity.getMealDeduction());

            // 允许一定范围内的精度误差
            if (calculatedGross.subtract(entity.getGrossSalary()).abs().compareTo(new BigDecimal("0.01")) > 0) {
                throw new RuntimeException(String.format("应发工资计算不正确，应为%.2f，实际为%.2f",
                        calculatedGross, entity.getGrossSalary()));
            }
        }

        // 自动计算社保公积金合计（如果没有提供的话）
        if (entity.getSocialHousingTotal() == null) {
            BigDecimal calculatedSocialHousing = BigDecimal.ZERO;
            if (entity.getPensionDeduction() != null)
                calculatedSocialHousing = calculatedSocialHousing.add(entity.getPensionDeduction());
            if (entity.getUnemploymentDeduction() != null)
                calculatedSocialHousing = calculatedSocialHousing.add(entity.getUnemploymentDeduction());
            if (entity.getMedicalDeduction() != null)
                calculatedSocialHousing = calculatedSocialHousing.add(entity.getMedicalDeduction());
            if (entity.getMajorMedicalDeduction() != null)
                calculatedSocialHousing = calculatedSocialHousing.add(entity.getMajorMedicalDeduction());
            if (entity.getHousingFundPersonal() != null)
                calculatedSocialHousing = calculatedSocialHousing.add(entity.getHousingFundPersonal());
            entity.setSocialHousingTotal(calculatedSocialHousing);
        } else {
            // 校验社保存积金合计
            BigDecimal calculatedSocialHousing = BigDecimal.ZERO;
            if (entity.getPensionDeduction() != null)
                calculatedSocialHousing = calculatedSocialHousing.add(entity.getPensionDeduction());
            if (entity.getUnemploymentDeduction() != null)
                calculatedSocialHousing = calculatedSocialHousing.add(entity.getUnemploymentDeduction());
            if (entity.getMedicalDeduction() != null)
                calculatedSocialHousing = calculatedSocialHousing.add(entity.getMedicalDeduction());
            if (entity.getMajorMedicalDeduction() != null)
                calculatedSocialHousing = calculatedSocialHousing.add(entity.getMajorMedicalDeduction());
            if (entity.getHousingFundPersonal() != null)
                calculatedSocialHousing = calculatedSocialHousing.add(entity.getHousingFundPersonal());

            if (calculatedSocialHousing.compareTo(entity.getSocialHousingTotal()) != 0) {
                throw new RuntimeException(String.format("社保公积金合计计算不正确，应为%.2f，实际为%.2f",
                        calculatedSocialHousing, entity.getSocialHousingTotal()));
            }
        }

        // 自动计算税前工资（如果没有提供的话）
        if (entity.getTaxableSalary() == null) {
            BigDecimal taxableSalary = entity.getGrossSalary() != null ? entity.getGrossSalary() : BigDecimal.ZERO;
            if (entity.getSocialHousingTotal() != null) {
                taxableSalary = taxableSalary.subtract(entity.getSocialHousingTotal());
            }
            entity.setTaxableSalary(taxableSalary);
        }

        // 自动计算实发工资（如果没有提供的话）
        if (entity.getNetSalary() == null) {
            BigDecimal netSalary = entity.getTaxableSalary() != null ? entity.getTaxableSalary() : BigDecimal.ZERO;
            if (entity.getPersonalTax() != null) {
                netSalary = netSalary.subtract(entity.getPersonalTax());
            }
            entity.setNetSalary(netSalary);
        } else {
            // 校验实发工资
            BigDecimal calculatedNetSalary = entity.getTaxableSalary() != null ? entity.getTaxableSalary()
                    : BigDecimal.ZERO;
            if (entity.getPersonalTax() != null) {
                calculatedNetSalary = calculatedNetSalary.subtract(entity.getPersonalTax());
            }

            if (calculatedNetSalary.compareTo(entity.getNetSalary()) != 0) {
                throw new RuntimeException(String.format("实发工资计算不正确，应为%.2f，实际为%.2f",
                        calculatedNetSalary, entity.getNetSalary()));
            }
        }

        // 校验状态合法性
        if (StringUtils.isNotBlank(entity.getStatus()) &&
                !"0".equals(entity.getStatus()) && !"1".equals(entity.getStatus())) {
            throw new RuntimeException("状态只能是0(正常)或1(封存)");
        }

        // 校验数据来源合法性
        if (StringUtils.isNotBlank(entity.getDataSource()) &&
                !"1".equals(entity.getDataSource()) && !"2".equals(entity.getDataSource()) &&
                !"3".equals(entity.getDataSource()) && !"4".equals(entity.getDataSource())) {
            throw new RuntimeException("数据来源只能是1(导入)、2(调薪)、3(冲减)或4(修正)");
        }
    }
}
